package com.onlineauction.entities;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.List;

import net.sf.jsr107cache.Cache;

import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.Query;
import com.google.appengine.api.datastore.Query.FilterOperator;
import com.onlineauction.helpers.CacheHandler;
import com.onlineauction.helpers.Constants;

public class Bid extends GenericEntity implements Comparable<Bid> {

	private long auctionID;
	private String username;
	private Calendar bidTime;
	private double bidPrice;
	private long bidID;

	public Bid(long auctionID, String username, Calendar bidTime, double bidPrice, boolean toCreate) {
		this.auctionID = auctionID;
		this.username = username;
		this.bidTime = bidTime;
		this.bidPrice = bidPrice;

		if (toCreate) {
			this.createAndStoreBid();
		}
	}

	public Bid(long bidID) {
		Entity entity = getEntity(Constants.BID, bidID);
		if (entity != null) {
			this.bidID = entity.getKey().getId();
			this.username = (String) entity.getProperty(Constants.USERNAME);
			this.bidTime = (Calendar) entity.getProperty(Constants.BID_TIME);
			this.bidPrice = (Double) entity.getProperty(Constants.BID_PRICE);
			this.auctionID = (Long) entity.getProperty(Constants.AUCTION_ID);
		}
	}

	private void createAndStoreBid() {
		Entity entity = new Entity(Constants.BID);

		entity.setProperty(Constants.AUCTION_ID, this.auctionID);
		entity.setProperty(Constants.USERNAME, this.username);
		entity.setProperty(Constants.BID_TIME, this.bidTime);
		entity.setProperty(Constants.BID_PRICE, this.bidPrice);

		Key key = storeEntity(entity);
		if (key != null) {
			this.bidID = key.getId();
		}
	}

	public static List<Bid> getBidsOfAuction(long auctionID) {
		DatastoreService ds = DatastoreServiceFactory.getDatastoreService();
		@SuppressWarnings("deprecation")
		Query q = new Query(Constants.BID).addFilter(Constants.AUCTION_ID, FilterOperator.EQUAL,
				auctionID);

		Iterable<Entity> entities = ds.prepare(q).asIterable();
		List<Bid> bids = new ArrayList<Bid>();
		for (Entity entity : entities) {
			Bid bid = new Bid((Long) entity.getProperty(Constants.AUCTION_ID),
					(String) entity.getProperty(Constants.USERNAME),
					(Calendar) entity.getProperty(Constants.BID_TIME),
					(Double) entity.getProperty(Constants.BID_PRICE), false);
			bid.bidID = entity.getKey().getId();
			bids.add(bid);
		}
		return bids;
	}

	public static List<Bid> getBidsOfUser(String username) {
		DatastoreService ds = DatastoreServiceFactory.getDatastoreService();
		@SuppressWarnings("deprecation")
		Query q = new Query(Constants.BID).addFilter(Constants.USERNAME, FilterOperator.EQUAL,
				username);

		Iterable<Entity> entities = ds.prepare(q).asIterable();
		List<Bid> bids = new ArrayList<Bid>();
		for (Entity entity : entities) {
			Bid bid = new Bid((Long) entity.getProperty(Constants.AUCTION_ID),
					(String) entity.getProperty(Constants.USERNAME),
					(Calendar) entity.getProperty(Constants.BID_TIME),
					(Double) entity.getProperty(Constants.BID_PRICE), false);
			bid.bidID = entity.getKey().getId();
			bids.add(bid);
		}
		return bids;
	}

	public static Bid getBestBidOfAuction(long auctionID) {
		Cache auctionBidCache = CacheHandler.getAuctionBidCache();		
		if (null == auctionBidCache.get(auctionID)) {
			List<Bid> bids = getBidsOfAuction(auctionID);
			if (bids != null && bids.size() > 0) {
				Collections.sort(bids);
				Bid bestBid = bids.get(bids.size()-1);
				auctionBidCache.put(auctionID, bestBid);
				return bestBid;
			} else {
				return null;
			}
		} else {
			return (Bid)auctionBidCache.get(auctionID);
		}	
	}

	public long getAuctionID() {
		return auctionID;
	}

	public String getUsername() {
		return username;
	}

	public Calendar getBidTime() {
		return bidTime;
	}

	public double getBidPrice() {
		return bidPrice;
	}

	public long getBidID() {
		return bidID;
	}

	@Override
	public int compareTo(Bid otherBid) {
		return Double.compare(this.getBidPrice(), otherBid.getBidPrice());
	}

	@Override
	public boolean equals(Object otherBid) {
		if (this == otherBid) {
			return true;
		}
		if (!(otherBid instanceof Bid)) {
			return false;
		}
		if (Double.compare(this.getBidPrice(), ((Bid) otherBid).getBidPrice()) == 0) {
			return true;
		} else {
			return false;
		}
	}
}
